﻿using System;
using System.Configuration;
using System.Data.Common;
using System.IO;
using System.Runtime.CompilerServices;
namespace log4net.Util
{
    /// <summary>
    /// 解析web程序中的虚拟路径
    /// </summary>
    internal class ConnectionStringHelper
    {
  
        /// <summary>
        /// Extracts the Data Source file path from a connection string
        /// ~/ gets resolved as does |DataDirectory|
        /// </summary>

        public static string GetDataSourceFilePath(string connectionString)
        {
            

            DbConnectionStringBuilder builder = new DbConnectionStringBuilder();
            return GetDataSourceFilePath(builder, connectionString);
        }

  

        /// <summary>
        /// Converts the supplied connection string so that the Data Source 
        /// specification contains the full path and not ~/ or DataDirectory.
        /// </summary>

        public static string GetResolvedConnectionString(string connectionString)
        {
            
            DbConnectionStringBuilder builder = new DbConnectionStringBuilder();
            builder["Data Source"] = GetDataSourceFilePath(builder, connectionString);
            return builder.ToString();
        }

        [MethodImpl(MethodImplOptions.NoInlining)]
        private static string MapPath(string path)
        {
            return System.Web.Hosting.HostingEnvironment.MapPath(path);
        }

        private static string GetDataSourceFilePath(DbConnectionStringBuilder builder, string connectionString)
        {
            builder.ConnectionString = connectionString;
            if (!builder.ContainsKey("Data Source"))
                throw new ArgumentException("A 'Data Source' parameter was expected in the supplied connection string, but it was not found.");
            string dataSource = builder["Data Source"].ToString();
            return ResolveDataSourceFilePath(dataSource);
        }

        private static readonly char[] _dirSeparators = new char[] { Path.DirectorySeparatorChar };

        public static string ResolveDataSourceFilePath(string path)
        {
            const string dataDirectoryMacroString = "|DataDirectory|";

            //
            // Check to see if it starts with a ~/ and if so map it and return it.
            //
            //如果目录是~/开头的，直接映射物理路径后返回
            if (path.StartsWith("~/"))
                return MapPath(path);

            //
            // Else see if it uses the DataDirectory macro/substitution 
            // string, and if so perform the appropriate substitution.
            //
            //如果目录不是DataDirectory开头的，有可能已经是完全物理路径 ，所以直接返回
            if (!path.StartsWith(dataDirectoryMacroString, StringComparison.OrdinalIgnoreCase))
                return path;

            //
            // Look-up the data directory from the current AppDomain.
            // See "Working with local databases" for more:
            // http://blogs.msdn.com/smartclientdata/archive/2005/08/26/456886.aspx
            //
            //返回app_data目录路径
            string baseDirectory = AppDomain.CurrentDomain.GetData("DataDirectory") as string;

            //
            // If not, try the current AppDomain's base directory.
            //
            //当前应用程序程序目录路径
            if (string.IsNullOrEmpty(baseDirectory))
                baseDirectory = AppDomain.CurrentDomain.BaseDirectory;

            //
            // Piece the file path back together, taking leading and 
            // trailing backslashes into account to avoid duplication.
            //
            //最终返回完整的物理路径
            return  NullString(baseDirectory).TrimEnd(_dirSeparators)
                 + Path.DirectorySeparatorChar
                 + path.Substring(dataDirectoryMacroString.Length).TrimStart(_dirSeparators);
        }

        private static string NullString(string str)
        {
            return str ?? string.Empty;
        }

        private ConnectionStringHelper() { }
    }
}
